home *** CD-ROM | disk | FTP | other *** search
- /* OS- and machine-dependent stuff for UNIX */
- /* collected from a lot of other stuff from different releases of the package */
- /* Written by Mikel Matthews, N9DVG */
- /* SYS5 stuff added by Jere Sandidge, K4FUM */
- /* cleanup and adaption into NETCHL by PE1CHL */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <termio.h>
- #include <sys/types.h>
- #include <sys/times.h>
- #include <sys/ndir.h>
- #include <sys/select.h>
- #include <sys/stat.h>
- #include <prototypes.h>
-
- #include "global.h"
- #include "config.h"
- #include "mbuf.h"
- #include "internet.h"
- #include "iface.h"
- #include "cmdparse.h"
- #include "timer.h"
- #include "environ.h"
- #include "asy.h"
- #include "unix.h"
-
- #ifndef B19200
- #define B19200 EXTA
- #endif
-
- #ifndef B38400
- #define B38400 EXTB
- #endif
-
- #if (defined(FD_SETSIZE) && !defined(M_I86MM))
- #define SELECT /* we can use the select() call */
-
- # ifdef FD_ZERO
- # define bzero(s,n) memset(s,0,n) /* there is no bzero() in the lib! */
- # define NUL_SET {0}
- # else
- typedef unsigned long fd_set; /* equivalents of FD_xxx macros */
- # define FD_ZERO(fdsp) *(fdsp) = 0
- # define FD_SET(fd,fdsp) *(fdsp) |= (1 << (fd))
- # define FD_CLR(fd,fdsp) *(fdsp) &= ~(1 << (fd))
- # define FD_ISSET(fd,fdsp) (*(fdsp) & (1 << (fd)))
- # define NUL_SET 0
- # endif
- #endif
-
- struct asy asy[ASY_MAX];
- struct interface *ifaces;
-
- unsigned nasy = 0; /* number of ASY interfaces */
-
- #ifdef SERVERS
- extern FILE *logfp; /* log file pointer */
- extern char logname[]; /* log file name */
- #endif
-
- #ifdef TRACE
- extern FILE *trfp; /* trace file pointer */
- extern char trname[]; /* trace file name */
- #endif
-
- #ifdef IP
- extern struct mbuf *loopq;
- #endif
- #ifdef AX25
- extern struct mbuf *axloopq;
- #endif
-
- static struct termio saved_termio; /* termio on program startup */
- static struct termio our_termio; /* termio during program run */
-
- #ifdef SELECT
- static char *envselect; /* options passed using SELECT envvar */
- static int noselect = 0; /* # of fd's NOT supporting select */
- static int maxfd = 0; /* # of fd's for select() */
- static fd_set port_set = NUL_SET; /* set containing all serial devices */
- static fd_set read_set = NUL_SET; /* returned set from last select() */
- static prg_busy = 0; /* set when busy */
- #endif
-
- static char ttbuf[BUFSIZ]; /* buffer used for stdout buffering */
-
- /* Called at startup time to set up console I/O */
- ioinit()
- {
- #ifdef SELECT
- fd_set fdset; /* trial set for select */
- struct timeval timeout;
- #endif
-
- setbuf(stdout,ttbuf); /* buffering for stdout */
-
- tzset(); /* init the timezone variable */
-
- ioctl(0,TCGETA,&saved_termio); /* read and save termio state */
-
- /* copy termio and drop input processing, echo, and INTR signal */
- /* the VMIN/VTIME will be set up for immediate return when no key */
-
- ASSIGN(our_termio,saved_termio);
- our_termio.c_lflag &= ~(ICANON|ECHO);
- our_termio.c_cc[VINTR] = 0xff;
- our_termio.c_cc[VMIN] = 0;
- our_termio.c_cc[VTIME] = 0;
-
- #ifdef SELECT
- envselect = getnenv("SELECT"); /* get SELECT var settings */
-
- if (strchr(envselect,'k') != NULL) /* select() on keyboard? */
- {
- /* check if stdin can use select() */
-
- FD_ZERO(&fdset); /* setup an fd_set for stdin */
- FD_SET(0,&fdset);
- timeout.tv_sec = timeout.tv_usec = 0;
-
- if (select(1,&fdset,NULL,NULL,&timeout) < 0)
- {
- if (errno == EINVAL) /* no select() support */
- printf("warning: stdin device does not support select()\n");
- else
- perror("stdin select");
-
- noselect++;
- }
- else /* select() went okay */
- {
- maxfd = 1; /* select on fd #0 */
- FD_SET(0,&port_set); /* enter stdin in the select set */
- our_termio.c_cc[VMIN] = 1; /* can wait on read() */
- our_termio.c_cc[VTIME] = 2;
- }
- }
- else
- noselect++; /* no select on stdin */
- #endif
-
- ioctl(0,TCSETA,&our_termio); /* set our termio values */
- }
-
- /* Called just before exiting to restore console state */
- iostop()
- {
- while(ifaces != NULLIF){
- /* first flush the interface's buffers */
- while(ifaces->recv != NULLVFP && (*ifaces->recv)(ifaces))
- ;
- if(ifaces->stop != NULLFP)
- (*ifaces->stop)(ifaces);
- ifaces = ifaces->next;
- }
-
- ioctl(0,TCSETAW,&saved_termio); /* reset to original state */
- }
-
- /* Spawn subshell */
- doshell(argc,argv)
- int argc;
- char *argv[];
- {
- char *command,**envp;
- int ret;
-
- #ifdef SERVERS
- if (logfp != NULLFILE) /* logging to file? */
- fclose(logfp); /* close the logfile */
- #endif
-
- #ifdef TRACE
- if (trfp != stdout) /* trace to file? */
- fclose(trfp); /* close it during shell exec */
- #endif
-
- fflush(stdout);
-
- ioctl(0,TCSETAW,&saved_termio); /* set original terminal mode */
-
- if((command = getenv("SHELL")) == NULLCHAR)
- command = "/bin/sh"; /* default command interpreter */
-
- envp = make_env(); /* create envinronment array */
-
- switch (fork()) /* spawn a subprocess */
- {
- case -1: /* an error occurred... */
- perror("fork");
- ret = -1;
- break;
- case 0: /* this is the child */
- execve(command,argv,envp);
- perror(command);
- exit(1);
- default: /* this is the parent */
- wait(&ret); /* wait for child to terminate */
- break;
- }
-
- ioctl(0,TCSETAW,&our_termio); /* our terminal mode again */
-
- free_env(); /* free the envp and temp env */
-
- #ifdef SERVERS
- if (logfp != NULLFILE) /* re-open logfile if it was open */
- logfp = fopen(logname,"a+");
- #endif
-
- #ifdef TRACE
- if (trfp != stdout) /* re-open tracefile if not stdout */
- if ((trfp = fopen(trname,"a+")) == NULLFILE)
- trfp = stdout;
- #endif
-
- if (ret != 0)
- return -1;
-
- return 0;
- }
-
- /* checks the time then ticks and updates ISS */
- static time_t clkval = 0;
- void
- check_time()
- {
- int32 iss();
- time_t ntime;
- int maxticks = SEC2TICK(15); /* upper limit on delayed ticks */
- struct tms tms; /* dummy required by times() */
-
- if(clkval == 0){
- /* Executed only once */
- clkval = times(&tms);
- return;
- }
-
- ntime = times(&tms); /* read elapsed time */
-
- while(ntime != clkval){ /* Handle possibility of several missed ticks */
- #ifdef IP
- icmpclk(); /* Call this one before tick */
- #endif
- tick();
- #ifdef IP
- (void)iss();
- #endif
- if(maxticks--) /* check limit on ticks to handle */
- clkval++;
- else
- clkval = ntime; /* ignore any remaining ticks */
- }
- }
-
- /* Read characters from the keyboard, translating them to internal codes.
- * If none are ready, return -1
- * This piece of code crudely assumes that you are on an ANSI terminal...
- */
- int
- kbread()
- {
- int c;
- #ifdef SELECT
- struct timeval timeout;
-
- if (stdin->_cnt == 0 && /* no buffered characters? */
- maxfd > 0) /* select() allowed? */
- {
- read_set = port_set;
- timeout.tv_sec = timeout.tv_usec = 0;
-
- #ifdef IP
- if (loopq == NULLBUF) /* nothing on IP loopback? */
- #endif
- #ifdef AX25
- if (axloopq == NULLBUF) /* nothing on AX.25 loopb? */
- #endif
-
- if (noselect || prg_busy) /* reason to stay awake? */
- timeout.tv_usec = 20000; /* short sleeptime */
- else
- timeout.tv_sec = 1; /* sleep for a long time */
-
- prg_busy = 1; /* assume we are busy */
-
- if (select(maxfd,&read_set,NULL,NULL,&timeout) >= 0)
- {
- #ifdef DEBUG
- int i;
-
- printf("select:");
- for (i = 0; i < maxfd; i++)
- if (FD_ISSET(i,&read_set))
- printf(" %d",i);
- printf("\n");
- fflush(stdout);
- #endif
- }
- else
- {
- #ifdef DEBUG
- perror("select:");
- #endif
-
- return -1; /* error in select() */
- }
-
- if (FD_ISSET(0,&port_set) && !FD_ISSET(0,&read_set))
- return -1; /* select() says no input available */
- }
- #endif
-
- if((c = getchar()) == EOF)
- return -1; /* no input available */
-
- if(c == 0x1b){ /* ESC character? */
- /* Lead-in to a special char */
- if(getchar() != '[')
- return 0x1b;
-
- switch(c = getchar())
- {
- case 'M': /* F-1 key */
- c = -11;
- break;
- case 'N': /* F-2 key */
- c = -10;
- break;
- case 'O': /* F-3 key */
- c = -9;
- break;
- case 'P': /* F-4 key */
- c = -8;
- break;
- case 'Q': /* F-5 key */
- c = -7;
- break;
- case 'R': /* F-6 key */
- c = -6;
- break;
- case 'S': /* F-7 key */
- c = -5;
- break;
- case 'T': /* F-8 key */
- c = -4;
- break;
- case 'U': /* F-9 key */
- c = -3;
- break;
- case 'V': /* F-10 key */
- c = -2;
- break;
- case 'H': /* HOME key */
- c = -20;
- break;
- case 'A': /* UP arrow */
- c = -19;
- break;
- case 'I': /* PAGE UP */
- c = -18;
- break;
- case 'D': /* LEFT arrow */
- c = -17;
- break;
- case 'C': /* RIGHT arrow */
- c = -16;
- break;
- case 'F': /* END key */
- c = -15;
- break;
- case 'B': /* DOWN arrow */
- c = -14;
- break;
- case 'G': /* PAGE DOWN */
- c = -13;
- break;
- case 'L': /* INS key */
- c = -12;
- break;
- default: /* Dunno what it is */
- c = -1;
- }
- }
- return c;
- }
-
- /* Create a directory listing in a temp file and return the resulting file
- * descriptor. If full == 1, give a full listing; else return just a list
- * of names.
- */
- FILE *
- dir(path,full)
- char *path;
- int full;
- {
- char *tname;
- char *option;
- FILE *fp;
- char command[256];
-
- if ((tname = tmpnam(NULLCHAR)) == NULLCHAR)
- return NULLFILE;
-
- if (full < 0)
- option = "C";
- else
- if (full > 0)
- option = "l";
- else
- option = "1";
-
- sprintf(command,"ls -%s \"%s\" >%s",option,path,tname);
- system(command);
- fp = fopen(tname,"r");
- unlink(tname); /* unlink the file now, it remains open */
-
- return fp;
- }
-
- /* wildcard filename lookup */
- filedir(name,times,ret_str)
- char *name;
- int times;
- char *ret_str;
- {
- static char dname[128], fname[128];
- static DIR *dirp = NULL;
- struct direct *dp;
- struct stat sbuf;
- char *cp, temp[128];
-
- /*
- * Make sure that the \0 is there in case we don't find anything
- */
- ret_str[0] = '\0';
-
- if (times == 0) {
- /* default a null name to * */
- if (name == NULL || *name == '\0')
- name = "*";
- /* split path into directory and filename */
- if ((cp = strrchr(name,'/')) == NULL) {
- strcpy(dname,".");
- strcpy(fname,name);
- } else {
- strcpy(dname,name);
- dname[cp - name] = '\0';
- strcpy(fname,cp + 1);
- /* root directory */
- if (dname[0] == '\0')
- strcpy(dname,"/");
- /* trailing '/' */
- if (fname[0] == '\0')
- strcpy(fname,"*");
- }
- /* close directory left over from another call */
- if (dirp != NULL)
- closedir(dirp);
- /* open directory */
- if ((dirp = opendir(dname)) == NULL)
- return;
- } else {
- /* for people who don't check return values */
- if (dirp == NULL)
- return;
- }
-
- /* scan directory */
- while ((dp = readdir(dirp)) != NULL) {
- /* test for name match */
- if (wildmat(dp->d_name,fname)) {
- /* test for regular file */
- sprintf(temp,"%s/%s",dname,dp->d_name);
- if (stat(temp,&sbuf) < 0)
- continue;
- if ((sbuf.st_mode & S_IFMT) != S_IFREG)
- continue;
- strcpy(ret_str,dp->d_name);
- break;
- }
- }
-
- /* close directory if we hit the end */
- if (dp == NULL) {
- closedir(dirp);
- dirp = NULL;
- }
- }
-
- /* Initialize asynch port "dev" */
- int
- asy_init(dev,arg1,arg2,bufsize)
- int16 dev;
- char *arg1,*arg2; /* Attach args for address and vector */
- unsigned bufsize;
- {
- register struct asy *ap;
- struct termio sgttyb;
- #ifdef SELECT
- fd_set fdset; /* trial set for select */
- struct timeval timeout;
- #endif
-
- if (dev >= nasy)
- return -1;
-
- ap = &asy[dev];
-
- if ((ap->fd = open(arg1,O_RDWR,0)) < 0) {
- perror(arg1);
- return -1;
- }
-
- /*
- * when possible, close the port upon exec
- */
-
- fcntl(ap->fd,F_SETFD,1);
-
- /*
- * get the termio structure and save it
- */
-
- if (ioctl(ap->fd,TCGETA,&ap->orgmodes) < 0) {
- perror(arg1);
- return -1;
- }
-
- ASSIGN(sgttyb,ap->orgmodes);
-
- sgttyb.c_iflag = IGNBRK|IGNPAR; /* KISS/SLIP setup */
- sgttyb.c_oflag = 0;
- sgttyb.c_cflag = B9600|CS8|CREAD|CLOCAL; /* default to 9600 baud */
- sgttyb.c_lflag = 0;
- sgttyb.c_cc[VTIME] = 0;
- sgttyb.c_cc[VMIN] = 0;
-
- #ifdef CTSFLOW
- if (strchr(arg2,'c') != NULL) /* CTSFLOW? */
- sgttyb.c_cflag |= CTSFLOW;
-
- if (strchr(arg2,'r') != NULL) /* RTSFLOW? */
- sgttyb.c_cflag |= RTSFLOW;
- #endif
-
- #ifdef SELECT
- if (strchr(envselect,'t') != NULL) /* select() on ttys? */
- {
- /* check if this device supports select() */
-
- FD_ZERO(&fdset); /* setup an fd_set for this port */
- FD_SET(ap->fd,&fdset);
- timeout.tv_sec = timeout.tv_usec = 0;
-
- if (select(ap->fd + 1,&fdset,NULL,NULL,&timeout) < 0)
- {
- if (errno == EINVAL) /* no select() support */
- printf("warning: \"%s\" does not support select()\n",arg1);
- else
- perror(arg1);
-
- noselect++;
- }
- else
- {
- if (ap->fd >= maxfd)
- maxfd = ap->fd + 1;
-
- FD_SET(ap->fd,&port_set);
- sgttyb.c_cc[VMIN] = 1; /* read() can block on it */
- sgttyb.c_cc[VTIME] = 2;
- }
- }
- else
- noselect++; /* yet another one without select() */
- #endif
-
- if (ioctl(ap->fd,TCSETAF,&sgttyb) < 0) {
- perror(arg1);
- return -1;
- }
-
- ap->tty = malloc(strlen(arg1)+1); /* keep device name */
- strcpy(ap->tty,arg1);
-
- ap->buf = malloc(ap->bufsize = bufsize); /* receive buffer */
-
- return 0;
- }
- int
- asy_stop(iface)
- struct interface *iface;
- {
- register struct asy *ap;
-
- ap = &asy[iface->dev];
-
- if (ap->fd > 2) /* sanity check */
- ioctl(ap->fd,TCSETAW,&ap->orgmodes); /* restore tty state */
-
- close(ap->fd);
- }
- /* Asynchronous line I/O control */
- asy_ioctl(interface,argc,argv)
- struct interface *interface;
- int argc;
- char *argv[];
- {
- if (argc < 1) {
- printf("%u\n",asy[interface->dev].speed);
- return 0;
- }
-
- return asy_speed(interface->dev,atoi(argv[0]));
- }
- /* Set asynch line speed */
- int
- asy_speed(dev,speed)
- int16 dev;
- int speed;
- {
- struct termio sgttyb;
-
- if (dev >= nasy)
- return -1;
-
- asy[dev].speed = speed;
-
- if (ioctl(asy[dev].fd,TCGETA,&sgttyb) < 0) {
- perror(asy[dev].tty);
- return -1;
- }
-
- sgttyb.c_cflag &= ~CBAUD;
-
- switch ((unsigned)speed) {
- case 0:
- sgttyb.c_cflag |= B0;
- break;
- case 50:
- sgttyb.c_cflag |= B50;
- break;
- case 75:
- sgttyb.c_cflag |= B75;
- break;
- case 110:
- sgttyb.c_cflag |= B110;
- break;
- case 134:
- sgttyb.c_cflag |= B134;
- break;
- case 150:
- sgttyb.c_cflag |= B150;
- break;
- case 200:
- sgttyb.c_cflag |= B200;
- break;
- case 300:
- sgttyb.c_cflag |= B300;
- break;
- case 600:
- sgttyb.c_cflag |= B600;
- break;
- case 1200:
- sgttyb.c_cflag |= B1200;
- break;
- case 1800:
- sgttyb.c_cflag |= B1800;
- break;
- case 2400:
- sgttyb.c_cflag |= B2400;
- break;
- case 4800:
- sgttyb.c_cflag |= B4800;
- break;
- case 9600:
- sgttyb.c_cflag |= B9600;
- break;
- case 19200:
- sgttyb.c_cflag |= B19200;
- break;
- case 38400:
- sgttyb.c_cflag |= B38400;
- break;
- default:
- printf("asy_speed: Unknown speed (%d)\n",speed);
- break;
- }
-
- if (ioctl(asy[dev].fd,TCSETAW,&sgttyb) < 0) {
- perror(asy[dev].tty);
- return -1;
- }
-
- return 0;
- }
- /* Send a buffer to serial transmitter */
- asy_output(dev,buf,cnt)
- unsigned dev;
- char *buf;
- unsigned short cnt;
- {
- #ifdef DEBUG
- int i;
-
- printf("asy_output(%d,%lx,%d):",dev,buf,cnt);
- for (i = 0; i < cnt; i++)
- printf(" %02x",uchar(buf[i]));
-
- printf("\n");
- #endif
-
- #ifdef SELECT
- prg_busy = 3;
- #endif
-
- if (dev >= nasy || !stxrdy(dev))
- return -1;
-
- if (write(asy[dev].fd,buf,cnt) < cnt)
- return -1;
-
- return 0;
- }
- /* Receive characters from asynch line
- * Returns count of characters read
- */
- int16
- asy_recv(dev,buf,cnt)
- int16 dev;
- char *buf;
- unsigned cnt;
- {
- register struct asy *ap;
- unsigned tot = 0;
- int r;
-
- ap = &asy[dev];
-
- /* fill the read ahead buffer */
- if(ap->cnt == 0) {
- #ifdef SELECT
- if (FD_ISSET(ap->fd,&port_set) && !FD_ISSET(ap->fd,&read_set))
- return 0; /* select() indicates nothing there */
-
- FD_CLR(ap->fd,&read_set);
- #endif
-
- ap->data = ap->buf;
- if ((r = read(ap->fd,ap->data,ap->bufsize)) <= 0)
- return 0;
-
- ap->cnt = r;
-
- #ifdef DEBUG
- printf("asy_recv: read(%d) ",ap->cnt);
- for (r = 0; r < ap->cnt; r++)
- printf(" %02x",uchar(ap->data[r]));
-
- printf("\n");
- #endif
- }
- /* fetch what you need with no system call overhead */
- if(cnt == 1) { /* single byte copy, do it here */
- *buf = *ap->data++;
- ap->cnt--;
- tot++;
- } else { /* multi-byte copy, left memcpy do the work */
- r = min(cnt,ap->cnt);
- memcpy(buf,ap->data,r);
- ap->cnt -= r;
- ap->data += r;
- tot += r;
- }
-
- return (tot);
- }
- int
- stxrdy(dev)
- int16 dev;
- {
- #ifdef SELECT
- struct timeval timeout;
- fd_set write_set;
- int fd;
-
- fd = asy[dev].fd; /* the fd we want to check */
-
- if (FD_ISSET(fd,&port_set)) /* select() on this device? */
- {
- FD_ZERO(&write_set); /* write_fd = only that fd */
- FD_SET(fd,&write_set);
- read_set = port_set; /* read: all valid ports */
- timeout.tv_sec = timeout.tv_usec = 0;
-
- if (select(maxfd,&read_set,&write_set,NULL,&timeout) >= 0 &&
- !FD_ISSET(fd,&write_set))
- return 0; /* not ready */
- }
- #endif
- #if 0
- ioctl(asy[dev].fd,TCSBRK,1); /* wait for output to drain */
- #endif
- return 1;
- }
-
- /* find substring in another string */
-
- char *strstr (s,f)
- char *s,*f;
- {
- char *p;
-
- while ((p = strchr(s,*f)) != NULLCHAR)
- {
- if (!strncmp(p,f,strlen(f)))
- return p;
-
- s = p + 1;
- }
-
- return p;
- }
-
- #if (defined(M_I86MM))
- /* Convert a pointer to a long integer, so that it can be printed in a
- compiler- and system-independent way.
- This function currently assumes that pointers are 16-bit (int) size.
- */
- long ptr2long (p)
- char *p;
- {
- unsigned int rv = (unsigned int) p;
-
- return (long) rv;
- }
- #endif
-
- /* interrupt disable and enable have no real meaning here */
-
- char disable ()
-
- {
- return 0;
- }
-
- void restore (ps)
- char ps;
-
- {
- }
-
- /* this routine is supposed to give control to the system until something */
- /* is to be done. when select is unusable, wait a short period */
-
- void eihalt ()
-
- {
- #ifdef SELECT
- prg_busy &= ~1; /* apparently not active... */
-
- if (maxfd > 0) /* select() supported? */
- return; /* then no reason to wait */
- #endif
-
- nap(100L); /* when no select(), nap() */
- }
- ə